package org.dromara.patrol.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.constant.ReportRectifyResultConstants;
import org.dromara.common.core.enums.NoticeMessageType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.patrol.api.RemotePatrolSubtaskCommonService;
import org.dromara.patrol.domain.*;
import org.dromara.patrol.domain.bo.*;
import org.dromara.patrol.domain.vo.CalculateScoreVo;
import org.dromara.patrol.domain.vo.CalculatedItemScoreVo;
import org.dromara.patrol.domain.vo.PatrolReportVo;
import org.dromara.patrol.domain.vo.PatrolSubtaskCommonVo;
import org.dromara.patrol.mapper.*;
import org.dromara.patrol.service.IPatrolReportService;
import org.dromara.patrol.service.IPatrolSubtaskCommonService;
import org.dromara.system.api.RemoteMessageService;
import org.dromara.system.api.RemoteStoreService;
import org.dromara.system.api.RemoteTenantService;
import org.dromara.system.api.RemoteUserService;
import org.dromara.system.api.domain.bo.RemoteMessageBo;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.rmi.ServerException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 巡店管理-巡店报告Service业务层处理
 *
 * @author LionLi
 * @date 2024-03-25
 */
@Service
@Log4j2
@RequiredArgsConstructor
public class PatrolReportServiceImpl implements IPatrolReportService {

    private final PatrolReportMapper baseMapper;
    private final PatrolReportDetailMapper patrolReportDetailMapper;
    private final PatrolReportRectifyMapper patrolReportRectifyMapper;
    private final PatrolReportVerifyMapper patrolReportVerifyMapper;
    private final PatrolTemplateMapper patrolTemplateMapper;
    private final PatrolActionStatisticsMapper patrolActionStatisticsMapper;
    //  报表的公共任务
    private final IPatrolSubtaskCommonService patrolSubtaskCommonService;

    @DubboReference
    private RemoteMessageService remoteMessageService;
    @DubboReference
    private RemoteUserService remoteUserService;
    @DubboReference
    private RemoteTenantService remoteTenantService;
    @DubboReference
    private RemoteStoreService remoteStoreService;
    @DubboReference
    private RemotePatrolSubtaskCommonService remotePatrolSubtaskCommonService;

    /**
     * 查询巡店管理-巡店报告
     */
    @Override
    public PatrolReportVo queryById(Long reportId){
        PatrolReportVo patrolReportVo = baseMapper.selectVoById(reportId);
        if (patrolReportVo == null) {
            return null;
        }
        if (ObjUtil.isNotNull(patrolReportVo.getStoreId())) {
            List<Long> storeIds = CollUtil.newArrayList(patrolReportVo.getStoreId());
            Map<Long, String> groupMap = remoteStoreService.selectGroupNamesByStoreList(storeIds);
            patrolReportVo.setGroupName(groupMap.getOrDefault(patrolReportVo.getStoreId(), ""));
        }
        List<PatrolReportVo> rows = CollUtil.newArrayList(patrolReportVo);
        buildNameMap(rows);
        PatrolReportVo vo = rows.get(0);
        // 查询detail
        PatrolReportDetail detail = patrolReportDetailMapper.selectById(vo.getDetailId());
        vo.setDetail(detail.getDetails());
        return vo;
    }

    /**
     * 查询巡店管理-巡店报告列表
     */
    @Override
    public TableDataInfo<PatrolReportVo> queryPageList(PatrolReportQuery query, PageQuery pageQuery) {
        buildQueryParam(query);
        LambdaQueryWrapper<PatrolReport> lqw = buildQueryWrapper(query);
        IPage<PatrolReportVo> patrolReportVoIPage = baseMapper.selectVoPage(pageQuery.build(),lqw );
        List<PatrolReportVo> rows = patrolReportVoIPage.getRecords();
        if (CollUtil.isNotEmpty(rows)) {
            buildNameMap(rows);
            patrolReportVoIPage.setRecords(rows);
        }
        return TableDataInfo.build(patrolReportVoIPage);
    }

    /**
     * 构建nameMap
     * @param rows  报表数据
     */
    private void buildNameMap(List<PatrolReportVo> rows) {

        // 查询用户名称
        CompletableFuture<Map<Long, String>> userCompletableFuture = CompletableFuture.supplyAsync(() -> {
            List<Long> allUserIds = new ArrayList<>();
            List<Long> userIds = StreamUtils.toSet(rows, PatrolReportVo::getCreateBy).stream().toList();
            if (CollUtil.isNotEmpty(userIds)) {
                allUserIds.addAll(userIds);
            }
            List<Long> rectifyIds = StreamUtils.toSet(rows, PatrolReportVo::getRectifyPerson).stream().toList();
            if (CollUtil.isNotEmpty(rectifyIds)) {
                allUserIds.addAll(rectifyIds);
            }
            rows.stream().map(PatrolReportVo::getAssignRectifyPersons).filter(Objects::nonNull).forEach(allUserIds::addAll);

            return remoteUserService.selectNickNameByIds(allUserIds);
        });

        // 查询当前登录的租户名称
        CompletableFuture<Map<String, String>> tenantMapCompletableFuture = CompletableFuture.supplyAsync(() -> {
            List<String> tenantIds = StreamUtils.toSet(rows, PatrolReportVo::getTenantId).stream().toList();
            return remoteTenantService.selectNamesByTenantIds(tenantIds);
        });

        // 查询模版ids 名称
        CompletableFuture<Map<Long, String>> templateMapCompletableFuture = CompletableFuture.supplyAsync(() -> {
            List<Long> templateIds = StreamUtils.toSet(rows, PatrolReportVo::getTemplateId).stream().toList();
            List<PatrolTemplate> templates = patrolTemplateMapper.selectBatchIds(templateIds);
            return StreamUtils.toMap(templates, PatrolTemplate::getTemplateId, PatrolTemplate::getName);
        });

        // 查询门店ids 名称
        CompletableFuture<Map<Long, String>> storeMapCompletableFuture = CompletableFuture.supplyAsync(() -> {
            List<Long> storeIds = StreamUtils.toSet(rows, PatrolReportVo::getStoreId).stream().toList();
            return remoteStoreService.selectNamesByStoreList(storeIds);
        });

        // 构建任务id
        CompletableFuture<Map<Long, String>> taskMapCompletableFuture = CompletableFuture.supplyAsync(() -> {
            List<Long> taskIds = StreamUtils.toSet(rows, PatrolReportVo::getTaskId).stream().toList();
            return remotePatrolSubtaskCommonService.getPatrolTaskNameMap(taskIds);
        });

        // 等待所有异步任务完成，并返回结果
        CompletableFuture.allOf(userCompletableFuture, tenantMapCompletableFuture, templateMapCompletableFuture,
                storeMapCompletableFuture, taskMapCompletableFuture).join();


        rows.forEach(row-> {
            Map<String, String> nameMap = new HashMap<>();
            addIfNotNull(nameMap, row.getCreateBy(), userCompletableFuture.join());

            addIfNotNull(nameMap, row.getRectifyPerson(), userCompletableFuture.join());

            if (CollUtil.isNotEmpty(row.getAssignRectifyPersons())) {
                row.getAssignRectifyPersons().forEach(assignRectifyPerson -> {
                    addIfNotNull(nameMap, assignRectifyPerson, userCompletableFuture.join());
                });
            }

            // 模版名称
            addIfNotNull(nameMap, row.getTemplateId(), templateMapCompletableFuture.join());
            // 租户名称
            addIfNotNull(nameMap, row.getTenantId(), tenantMapCompletableFuture.join());
            // 门店名称
            addIfNotNull(nameMap, row.getStoreId(), storeMapCompletableFuture.join());
            // 构建任务id
            addIfNotNull(nameMap, row.getTaskId(), taskMapCompletableFuture.join());

            row.setNameMap(nameMap);
        });

    }

    /**
     * 向map中添加一个键值对，如果键不为null，则将该键及其对应的值从source map中获取，并添加到目标map中，
     * 如果source map中不存在该键，则将该键与空字符串对应，添加到目标map中。
     *
     * @param map    目标map
     * @param key    要添加的键
     * @param source 源map
     */
    private <K> void addIfNotNull(Map<String, String> map, K key, Map<K, String> source) {
        if (key != null) {
            map.put(key.toString(), source.getOrDefault(key, ""));
        }
    }

    private void buildQueryParam(PatrolReportQuery query) {
        //全部OWN_ALL,待我整改 OWN_CORRECTING,待我审核 OWN_VALIDATING
        String tableType = query.getTableType();
        if (StrUtil.isNotBlank(tableType) && !tableType.equals("OWN_ALL")){
            switch (tableType){
                //设置整改人id
                case "OWN_CORRECTING":
                    query.setRectifyPerson(LoginHelper.getLoginUser().getUserId());
                    query.setStatus("CORRECTING");
                    break;
                case "OWN_VALIDATING":
                    query.setCreateBy(LoginHelper.getLoginUser().getUserId());
                    query.setStatus("VALIDATING ");
                    break;
                default:
                    break;
            }
        }


    }

    /**
     * 查询巡店管理-巡店报告列表
     */
    @Override
    public List<PatrolReportVo> queryList(PatrolReportBo bo) {
        LambdaQueryWrapper<PatrolReport> lqw = buildQueryWrapper(bo);
        List<PatrolReportVo> rows = baseMapper.selectVoList(lqw);
        if (CollUtil.isNotEmpty(rows)) {
            buildNameMap(rows);
        }
        return rows;
    }


    private LambdaQueryWrapper<PatrolReport> buildQueryWrapper(PatrolReportQuery query) {
//        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PatrolReport> queryWrapper = Wrappers.lambdaQuery();
        if (query.getTableType() != null) {
            switch (query.getTableType()) {
                case "OWN_CORRECTING":
                    queryWrapper.eq(PatrolReport::getRectifyPerson, query.getRectifyPerson());
                    break;
                case "OWN_VALIDATING":
                    queryWrapper.eq(PatrolReport::getCreateBy, query.getCreateBy());
                    break;
            }
        }
        // 是否整改
        if (StringUtils.isNotEmpty(query.getHaveRectify())) {
            if (Boolean.parseBoolean(query.getHaveRectify())) {
                queryWrapper.isNotNull(PatrolReport::getRectifyPerson);
            } else {
                queryWrapper.isNull(PatrolReport::getRectifyPerson);
            }
        }
      // 其他条件
        queryWrapper
                .eq(StringUtils.isNotBlank(query.getTaskId()), PatrolReport::getTaskId, query.getTaskId())
                .eq((StringUtils.isNotBlank(query.getStatus())), PatrolReport::getStatus, query.getStatus())
                .eq((StringUtils.isNotBlank( query.getAllRectifyPersons())), PatrolReport::getRectifyPerson, query.getAllRectifyPersons())
                .eq((StringUtils.isNotBlank(query.getPatrolSubType())), PatrolReport::getPatrolSubType, query.getPatrolSubType())
                .eq((StringUtils.isNotBlank(query.getPatrolType())), PatrolReport::getPatrolType, query.getPatrolType())
                .le((StringUtils.isNotBlank(query.getScoreEnd())), PatrolReport::getScore, query.getScoreEnd())
                .ge((StringUtils.isNotBlank(query.getScoreStart())), PatrolReport::getScore, query.getScoreStart())
                .le(query.getEndTime() != 0, PatrolReport::getInspectEndTime, query.getEndTime())
                .ge(query.getStartTime() != 0, PatrolReport::getInspectStartTime, query.getStartTime())
                .in(CollUtil.isNotEmpty(query.getStoreIds())  , PatrolReport::getStoreId, query.getStoreIds())
                .in(CollUtil.isNotEmpty(query.getTemplateIds()) , PatrolReport::getTemplateId, query.getTemplateIds())
                .in(CollUtil.isNotEmpty(query.getCreators()), PatrolReport::getCreateBy, query.getCreators())
                .in(CollUtil.isNotEmpty( query.getPatrolTypes()), PatrolReport::getPatrolType, query.getPatrolTypes())
                .orderByDesc(PatrolReport::getCreateTime);;
        return queryWrapper;
    }

    private LambdaQueryWrapper<PatrolReport> buildQueryWrapper(PatrolReportBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PatrolReport> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getFinalScore() != null, PatrolReport::getFinalScore, bo.getFinalScore());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), PatrolReport::getStatus, bo.getStatus());
        lqw.eq(bo.getTotalScore() != null, PatrolReport::getTotalScore, bo.getTotalScore());
        lqw.like(StringUtils.isNotBlank(bo.getName()), PatrolReport::getName, bo.getName());
        lqw.eq(bo.getScore() != null, PatrolReport::getScore, bo.getScore());
        lqw.eq(bo.getTaskId() != null, PatrolReport::getTaskId, bo.getTaskId());
        lqw.eq(bo.getStoreId() != null, PatrolReport::getStoreId, bo.getStoreId());
        lqw.eq(StringUtils.isNotBlank(bo.getType()), PatrolReport::getType, bo.getType());
        lqw.eq(StringUtils.isNotBlank(bo.getSubType()), PatrolReport::getSubType, bo.getSubType());
        lqw.eq(StringUtils.isNotBlank(bo.getPatrolType()), PatrolReport::getPatrolType, bo.getPatrolType());
        lqw.eq(StringUtils.isNotBlank(bo.getPatrolSubType()), PatrolReport::getPatrolSubType, bo.getPatrolSubType());
        lqw.eq(StringUtils.isNotBlank(bo.getHandler()), PatrolReport::getHandler, bo.getHandler());
        lqw.eq(bo.getInspectStartTime() != null, PatrolReport::getInspectStartTime, bo.getInspectStartTime());
        lqw.eq(bo.getInspectEndTime() != null, PatrolReport::getInspectEndTime, bo.getInspectEndTime());
        lqw.eq(StringUtils.isNotBlank(bo.getInspectPicture()), PatrolReport::getInspectPicture, bo.getInspectPicture());
        lqw.eq(bo.getRectifyNumber() != null, PatrolReport::getRectifyNumber, bo.getRectifyNumber());
        lqw.eq(bo.getRectifyPerson() != null, PatrolReport::getRectifyPerson, bo.getRectifyPerson());
        lqw.eq(bo.getProblemNumber() != null, PatrolReport::getProblemNumber, bo.getProblemNumber());
        lqw.eq(StringUtils.isNotBlank(bo.getMarkStrategy()), PatrolReport::getMarkStrategy, bo.getMarkStrategy());
        lqw.eq(StringUtils.isNotBlank(bo.getCustomizedReport()), PatrolReport::getCustomizedReport, bo.getCustomizedReport());
        lqw.eq(StringUtils.isNotBlank(bo.getProcessPatrolReport()), PatrolReport::getProcessPatrolReport, bo.getProcessPatrolReport());
        lqw.eq(bo.getProcessInstanceId() != null, PatrolReport::getProcessInstanceId, bo.getProcessInstanceId());
        lqw.eq(StringUtils.isNotBlank(bo.getVer()), PatrolReport::getVer, bo.getVer());
        lqw.eq(bo.getDuration() != null, PatrolReport::getDuration, bo.getDuration());
        lqw.eq(StringUtils.isNotBlank(bo.getCanBeDeleted()), PatrolReport::getCanBeDeleted, bo.getCanBeDeleted());
        lqw.eq(bo.getDetailId() != null, PatrolReport::getDetailId, bo.getDetailId());
        lqw.eq(bo.getScoreRate() != null, PatrolReport::getScoreRate, bo.getScoreRate());
        lqw.eq(bo.getTemplateId() != null, PatrolReport::getTemplateId, bo.getTemplateId());
        lqw.eq(bo.getCheckItemNumber() != null, PatrolReport::getCheckItemNumber, bo.getCheckItemNumber());
        lqw.eq(bo.getInspectedNumber() != null, PatrolReport::getInspectedNumber, bo.getInspectedNumber());
        lqw.eq(bo.getRectifyDoneTime() != null, PatrolReport::getRectifyDoneTime, bo.getRectifyDoneTime());
        //lqw.eq(StringUtils.isNotBlank(bo.getAssignRectifyPersons()), PatrolReport::getAssignRectifyPersons, bo.getAssignRectifyPersons());
        lqw.eq(bo.getStepStartTime() != null, PatrolReport::getStepStartTime, bo.getStepStartTime());
        lqw.eq(StringUtils.isNotBlank(bo.getAllNoScoring()), PatrolReport::getAllNoScoring, bo.getAllNoScoring());
       // lqw.eq(StringUtils.isNotBlank(bo.getCalculatedItemScore()), PatrolReport::getCalculatedItemScore, bo.getCalculatedItemScore());
        lqw.eq(StringUtils.isNotBlank(bo.getIsCheckDraft()), PatrolReport::getIsCheckDraft, bo.getIsCheckDraft());
        return lqw;
    }

    /**
     * 新增巡店管理-巡店报告
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean insertByBo(PatrolReportBo bo) {
        // 保存巡店子信息
        saveReportDetail(bo);
        BigDecimal totalScore = bo.getTotalScore();
        BigDecimal finalScore = bo.getFinalScore();
        if (totalScore.compareTo(BigDecimal.ZERO) > 0 && finalScore.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal multiply = finalScore.divide(totalScore, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));
            bo.setScoreRate(multiply);
        }

        String storeName = remoteStoreService.selectNameByStoreId(bo.getStoreId());
        if (StrUtil.isNotBlank(storeName)) {
            // 门店名称-202403081433
            bo.setName(storeName + "-" + DateUtils.dateTimeNow());
        }
        long time = new Date().getTime();
        bo.setType("PATROL");
        bo.setSubType("NORMAL");
        Long startTime = RedisUtils.getCacheObject(bo.getInspectTimeUuid());
        if (null == startTime) {
            throw new ServiceException("非法的请求方法");
        }
        bo.setInspectStartTime(startTime);
        bo.setInspectEndTime(time);
        bo.setDuration(time - startTime);

        bo.setProcessPatrolReport("1");
        if ("COMMITTED".equals(bo.getStatus())) {
            bo.setRectifyDoneTime(time);
        }
        // 保存主要信息
        Set<Long> ids = new HashSet<>();
        if (CollUtil.isNotEmpty(bo.getAssignRectifyPersons())) {
            ids.addAll(bo.getAssignRectifyPersons());
        }
        if (bo.getRectifyPerson() != null) {
            ids.add(bo.getRectifyPerson());
        }
        if (CollUtil.isNotEmpty(ids)) {
            bo.setStepHandlers(ids.stream().toList());
        }
        PatrolActionStatistics actionStatistics = new PatrolActionStatistics();
        PatrolReport add = MapstructUtils.convert(bo, PatrolReport.class);
        assert add != null;
        // 设置任务的完成时间
        if (bo.getTaskId() != null) {
            patrolSubtaskCommonService.updateStatusAndTimeById(bo.getTaskId(), "FINISH", null, time);
            actionStatistics.setFreePatrol(0);
            actionStatistics.setTaskPatrol(1);
        } else {
            actionStatistics.setFreePatrol(1);
            actionStatistics.setTaskPatrol(0);
        }

        // 设置逾期状态
        setOverdueStatus(bo, time, add);

        validEntityBeforeSave(add);
        add.setIsCheckDraft("1");
        boolean flag = baseMapper.insertOrUpdate(add);
        if (flag) {
            bo.setReportId(add.getReportId());
            bo.setCreateBy(add.getCreateBy());
            // 发送消息
            CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
                List<RemoteMessageBo> rectifyMessageList = buildMsg(storeName, bo);
                // 是否发送整改人消息
                sendMsg(rectifyMessageList);
            });
            // 保存数据给巡店行为统计表
            CompletableFuture<Void> voidCompletableFuture1 = CompletableFuture.runAsync(() -> {
                buildStatisticsMsg(actionStatistics, bo, ids.stream().toList());
                actionStatistics.setTenantId(add.getTenantId());
                patrolActionStatisticsMapper.insert(actionStatistics);
            });
            CompletableFuture.allOf(voidCompletableFuture, voidCompletableFuture1).join();
        }

        return flag;
    }

    private void buildStatisticsMsg(PatrolActionStatistics actionStatistics, PatrolReportBo bo, List<Long> ids) {
        actionStatistics.setUserId(bo.getCreateBy());
        try {
            Long groupId = remoteStoreService.selectGroupIdByStoreId(bo.getStoreId());
            actionStatistics.setGroupId(groupId);
        } catch (Exception e ) {
            log.info("未查询到门店");
        }

        actionStatistics.setStoreId(bo.getStoreId());
        actionStatistics.setReportId(bo.getReportId());
        actionStatistics.setLastPatrolTime(new Date().getTime());
        actionStatistics.setTotalScore(bo.getTotalScore());
        actionStatistics.setProblemNumber(bo.getProblemNumber());
        actionStatistics.setCheckItemNumber(Math.toIntExact(bo.getCheckItemNumber()));
        actionStatistics.setDuration(bo.getDuration());
        actionStatistics.setRectifyNumber(Math.toIntExact(bo.getRectifyNumber()));
        actionStatistics.setNotApplicableNumber(bo.getNotApplicableNumber());
        if ("PATROL_REALTIME".equals(bo.getPatrolType())) {
            actionStatistics.setRealTimePatrol(1);
        } else {
            actionStatistics.setRealTimePatrol(0);
        }

        if ("PATROL_LIVE".equals(bo.getPatrolType())) {
            actionStatistics.setLivePatrol(1);
        } else {
            actionStatistics.setLivePatrol(0);
        }

        if ("PATROL_VIDEO".equals(bo.getPatrolType())) {
            actionStatistics.setVideoPatrol(1);
        } else {
            actionStatistics.setVideoPatrol(0);
        }

        // 模版
        if ("PATROL_TEMPLATE".equals(bo.getPatrolSubType())) {
            actionStatistics.setTemplatePatrol(1);
        } else {
            actionStatistics.setTemplatePatrol(0);
        }

        if ("PATROL_USER_DEFINED".equals(bo.getPatrolSubType())) {
            actionStatistics.setCustomPatrol(1);
        } else {
            actionStatistics.setCustomPatrol(0);
        }

        actionStatistics.setAssignRectifyPersons(ids);
        if (CollUtil.isNotEmpty(ids)) {
            actionStatistics.setRectifyPass(1);
        }
        actionStatistics.setScore(bo.getScore());
        actionStatistics.setTotalScore(bo.getTotalScore());

    }


    /**
     * 发送通报人消息
     * @param storeName     门店名称
     * @param bo            报告对象
     * @return              远程消息对象
     */
    private List<RemoteMessageBo> buildMsg(String storeName, PatrolReportBo bo) {
        List<RemoteMessageBo> msgList = CollUtil.newArrayList();
        String handlerIds = bo.getHandler();
        List<Long> handlerIdList = null;
        if (StrUtil.isNotBlank(handlerIds)) {
            handlerIdList = Arrays.stream(handlerIds.split(",")).map(Long::parseLong).collect(Collectors.toList());
        }

        List<Long> rectifyIds = bo.getStepHandlers();
        String status = CollUtil.isEmpty(rectifyIds) ? "COMMITTED" : bo.getStatus();
        bo.setStatus(status);

        if ("COMMITTED".equals(bo.getStatus())) {
            // 只发送通知消息
            // 构建通报人消息
            if (CollUtil.isNotEmpty(handlerIdList)) {
                List<RemoteMessageBo> handlerMsg = buildSendMessage(storeName, handlerIdList, null, bo);
                msgList.addAll(handlerMsg);
            }
        } else {
            Map<Long, String> userMap = remoteUserService.selectNickNameByIds(rectifyIds);
            // 获取userMap中的值，并使用逗号拼接
            String rectifyPersonNames = CollUtil.join(userMap.values(), ",");
            List<RemoteMessageBo> rectifyMsg = buildSendMessage(storeName, rectifyIds, rectifyPersonNames, bo);
            msgList.addAll(rectifyMsg);

            // 构建通知人消息
            // 如果通知人和整改人相同，则不需要发送通知消息
            if (CollUtil.isNotEmpty(handlerIdList)) {
                handlerIdList.removeIf(rectifyIds::contains);
                if (CollUtil.isNotEmpty(handlerIdList)) {
                    List<RemoteMessageBo> handlerMsg = buildSendMessage(storeName, handlerIdList, rectifyPersonNames, bo);
                    msgList.addAll(handlerMsg);
                }
            }
        }

        return msgList;
    }

    private List<RemoteMessageBo> buildSendMessage(String storeName, List<Long> handlerIds, String rectifyPersonNames, PatrolReportBo reportBo) {

        return handlerIds.stream().map(userId -> {
            RemoteMessageBo bo = new RemoteMessageBo();
            bo.setSendId(reportBo.getCreateBy());
            bo.setRecordId(userId);
            //  湖北测试中 需要整改，处理人：aaaaa,sunchenbo
            // 湖北测试中店的巡店报告“湖北测试中-202404031931”已生成，请及时查看\n满分：60.00分，得分：0.00分
            String msg;
            if (StrUtil.isBlank(rectifyPersonNames)) {
                // msg = storeName + "的巡店报告\"" + reportBo.getName() + "\"已生成，请及时查看\n满分：" + reportBo.getTotalScore() + "分，得分：" + reportBo.getFinalScore() + "分";
                bo.setType(NoticeMessageType.NOTICE_PATROL_REPORT_COMMITTED);
                msg = NoticeMessageType.NOTICE_PATROL_REPORT_COMMITTED.getAlert().formatted(storeName, reportBo.getName(), reportBo.getTotalScore(), reportBo.getFinalScore());
                bo.setTitle(NoticeMessageType.NOTICE_PATROL_REPORT_COMMITTED.getTitle());
                bo.setMessageContent(msg);
            }else {
                bo.setType(NoticeMessageType.NOTICE_PROCESS_PATROL);

                msg = NoticeMessageType.NOTICE_PROCESS_PATROL.getAlert().formatted(storeName, "整改",rectifyPersonNames);
                bo.setTitle(msg);
                bo.setMessageContent(msg);
            }
            bo.setTitle(msg);
            bo.setStatus("0");
            bo.setUrl("/inspectionManagement/report/singleReportDetail?reportId=" + reportBo.getReportId());

            bo.setCreateBy(reportBo.getCreateBy());
            bo.setUpdateBy(reportBo.getCreateBy());
            return bo;
        }).toList();
    }


    /**
     * 根据任务ID和当前时间设置巡逻报告是否逾期的状态
     *
     * @param bo 巡逻报告Bo
     * @param time 当前时间
     * @param add 巡逻报告
     */
    private void setOverdueStatus(PatrolReportBo bo, long time, PatrolReport add) {
        // 如果存在任务id，那么需要判断是否逾期
        if (bo.getTaskId() != null) {
            // 查询任务信息
            PatrolSubtaskCommonVo taskInfo = patrolSubtaskCommonService.queryById(bo.getTaskId());
            Long executeEndTime = taskInfo.getExecuteEndTime();
            if (null == executeEndTime) {
                throw new ServiceException("任务未结束");
            }
            // 判断当前时间与executeEndTime，如果当前时间晚于executeEndTime, 那么需要将状态设置为逾期
            if (time > executeEndTime) {
                add.setExecutableWhenOverdue("0");
            } else {
                add.setExecutableWhenOverdue("1");
            }
        } else {
            add.setExecutableWhenOverdue("1");
        }
    }

    /**
     * 修改巡店管理-巡店报告
     */
    @Override
    public Boolean updateByBo(PatrolReportBo bo) {
        PatrolReport update = MapstructUtils.convert(bo, PatrolReport.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(PatrolReport entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除巡店管理-巡店报告
     */
    @Override
    @Transactional
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        // 删除行为统计基础数据
        patrolActionStatisticsMapper.delete(new LambdaUpdateWrapper<PatrolActionStatistics>()
                .in(PatrolActionStatistics::getReportId, ids));
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 计算得分评分项
     *
     * @param calculateScoreBo
     * @return
     */
    @Override
    public CalculateScoreVo calculateScore(CalculateScoreBo calculateScoreBo) {
        List<PatrolTemplateNodeBo> nodes = calculateScoreBo.getNodes();

        //构建一个评分集合
        List<PatrolTemplateNodeBo> buildNodes = buildNodes(nodes);

        //评分项集合
        List<PatrolTemplateNodeBo> totalScoreList = buildNodes.stream()
                .filter(node -> node.getIsItem().equals("0")).collect(Collectors.toList());
       //模版总分
        BigDecimal totalScoreTem = totalScoreList.stream().map(PatrolTemplateNodeBo::getScore).
                reduce(BigDecimal.ZERO, BigDecimal::add);
        //没问题评分项
        BigDecimal noProblemScore = totalScoreList.stream().filter(node -> node.getReportRectifyResult().
                        equals(ReportRectifyResultConstants.NO_PROBLEM)).
                map(PatrolTemplateNodeBo::getScore).reduce(BigDecimal.ZERO, BigDecimal::add);
        //有问题评分项
        BigDecimal hasProblemScore = totalScoreList.stream().filter(node -> node.getReportRectifyResult().
                        equals(ReportRectifyResultConstants.HAS_PROBLEM)).
                map(PatrolTemplateNodeBo::getScore).reduce(BigDecimal.ZERO, BigDecimal::add);
        //不适用评分项
        BigDecimal notApplyScore = totalScoreList.stream().filter(node -> node.getReportRectifyResult().
                        equals(ReportRectifyResultConstants.NOT_APPLY)).
                map(PatrolTemplateNodeBo::getScore).reduce(BigDecimal.ZERO, BigDecimal::add);

        //评分项总得分
        return getCalculateScoreVo(totalScoreTem, hasProblemScore, notApplyScore);
    }

    @Override
    public int approval(PatrolApprovalBo bo) {
        Long userId = LoginHelper.getUserId();
        // // 查询报表信息
        List<PatrolReportVerifyBo> dataList = bo.getData();
        Optional<Long> first = dataList.stream().map(PatrolReportVerifyBo::getReportId).filter(ObjUtil::isNotNull).findFirst();
        if (first.isEmpty()) {
            throw new ServiceException("请选择报告");
        }
        PatrolReport patrolReport = baseMapper.selectById(first.get());
        if (ObjUtil.isNull(patrolReport)) {
            throw new ServiceException("报告不存在");
        }
        if (!userId.equals(patrolReport.getCreateBy())) {
            throw new ServiceException("您没有权限审批报告");
        }

        String status = patrolReport.getStatus();
        // 如果状态不是待审核，则不允许审批
        if (!StrUtil.equals("VALIDATING", status)) {
            log.info("当前报告状态为：{}", status);
            throw new ServiceException("当前报告状态不能审批");
        }
        // 查询行为统计信息
        List<PatrolActionStatistics> patrolActionStatisticsList = patrolActionStatisticsMapper.selectList(new LambdaQueryWrapper<PatrolActionStatistics>()
                .eq(PatrolActionStatistics::getReportId, patrolReport.getReportId()));
        PatrolActionStatistics patrolActionStatistics = null;
        if (CollUtil.isNotEmpty(patrolActionStatisticsList)) {
            patrolActionStatistics = patrolActionStatisticsList.get(0);
        }

        // 如果状态为待整改，需要发送消息 并且修改stepHandlers
        Set<Long> ids = new HashSet<>();
        // AGAIN_RECTIFY
        dataList.stream().filter(a-> "AGAIN_RECTIFY".equals(a.getVerifyStatus())).findFirst()
                .ifPresent(a-> {
                    ids.add(a.getRectifyId());
                });
        if (CollUtil.isNotEmpty(ids)) {
            List<Long> idList = patrolReport.getStepHandlers();
            idList.addAll(ids.stream().toList());
            patrolReport.setStepHandlers(idList);
            String storeName = remoteStoreService.selectNameByStoreId(patrolReport.getStoreId());

            PatrolReportBo patrolReportBo = BeanUtil.toBean(patrolReport, PatrolReportBo.class);
            List<RemoteMessageBo> rectifyMessageList = buildMsg(storeName, patrolReportBo);
            // 是否发送整改人消息
            sendMsg(rectifyMessageList);
            patrolReport.setStatus("CORRECTING");
            if (ObjUtil.isNotNull(patrolActionStatistics)) {
                patrolActionStatistics.setRectifyPass(1);
            }
        } else {
            patrolReport.setStatus("COMMITTED");
            // 修改统计行为
            if (ObjUtil.isNotNull(patrolActionStatistics)) {
                patrolActionStatistics.setRectifyPass(0);
            }

        }
        if (ObjUtil.isNotNull(patrolActionStatistics)) {
            patrolActionStatistics.setRectifyPass(0);
            patrolActionStatisticsMapper.updateById(patrolActionStatistics);
        }

        // 添加审批记录
        List<PatrolReportVerify> patrolReportVerifies = BeanUtil.copyToList(dataList, PatrolReportVerify.class);
        patrolReportVerifyMapper.insertBatch(patrolReportVerifies);
        return baseMapper.updateById(patrolReport);
    }

    /**
     * 校验并整改巡店报告
     *
     * @param bo 巡店报告对象
     * @return 更新是否成功
     * @throws ServiceException 如果当前报表不是待整改状态，或者您不是当前报表的整改人，或者详细情况不存在
     */
    @Override
    @Transactional
    public int rectify(PatrolRectifyBo bo) {
        Long userId = LoginHelper.getUserId();
        // // 如果不是待整改状态
        if (!StrUtil.equals("CORRECTING", bo.getCurrentReportStatus())) {
            throw new ServiceException("当前报表不是待整改状态");
        }

        // // 查询报表信息
        List<PatrolReportRectifyBo> dataList = bo.getData();
        Optional<Long> first = dataList.stream().map(PatrolReportRectifyBo::getReportId).filter(ObjUtil::isNotNull).findFirst();
        if (first.isEmpty()) {
            throw new ServiceException("请选择报告");
        }
        PatrolReport patrolReport = baseMapper.selectById(first.get());
        if (ObjUtil.isNull(patrolReport)) {
            throw new ServiceException("报告不存在");
        }

        List<Long> stepHandlers = patrolReport.getStepHandlers();
        if (CollUtil.isEmpty(stepHandlers)) {
            throw new ServiceException("请指定处理人");
        }
        // JSONArray jsonArray = JSONUtil.parseArray(stepHandlers.toString());
        // List<Long> list = JSONUtil.toList(jsonArray, Long.class);
        if (!stepHandlers.contains(userId)) {
            throw new ServiceException("您没有权限整改报告");
        }

        stepHandlers.removeIf(item -> item.equals(userId));
        if (CollUtil.isEmpty(stepHandlers)) {
            patrolReport.setStatus("VALIDATING");
        } else {
            patrolReport.setStatus("CORRECTING");
        }
        patrolReport.setStepHandlers(stepHandlers);
        this.baseMapper.updateById(patrolReport);

        // 发送待审核消息列表
        RemoteMessageBo messageBo = new RemoteMessageBo();
        messageBo.setType(NoticeMessageType.NOTICE_PATROL_REPORT_VALIDATING);
        messageBo.setMessageContent(NoticeMessageType.NOTICE_PATROL_REPORT_VALIDATING.getAlert());
        messageBo.setTitle(NoticeMessageType.NOTICE_PATROL_REPORT_VALIDATING.getTitle());
        messageBo.setUrl("/inspectionManagement/report/singleReportDetail?reportId=" + patrolReport.getReportId());
        messageBo.setStatus("0");
        messageBo.setSendId(LoginHelper.getUserId());
        messageBo.setRecordId(patrolReport.getCreateBy());
        messageBo.setCreateBy(LoginHelper.getUserId());
        messageBo.setUpdateBy(LoginHelper.getUserId());

        try {
            remoteMessageService.insertByBo(messageBo);
        } catch (ServerException e) {
            throw new ServiceException("发送审核消息失败" + e.getMessage());
        }


        List<PatrolReportRectify> patrolReportRectifies = BeanUtil.copyToList(dataList, PatrolReportRectify.class);
        boolean b = patrolReportRectifyMapper.insertBatch(patrolReportRectifies);
        return b ? 1 : 0;
    }

    @Override
    public Long checkDraft(PatrolReportBo bo) {
        bo.setIsCheckDraft("0");
        // 保存详细信息
        saveReportDetail(bo);

        PatrolReport add = MapstructUtils.convert(bo, PatrolReport.class);
        boolean b = baseMapper.insertOrUpdate(add);
        if (b) {
            assert add != null;
            return add.getReportId();
        }

        throw new ServiceException("保存失败");
    }

    @Override
    public PatrolReport selectByTaskId(Long taskId) {
        List<PatrolReport> patrolReports = baseMapper.selectList(new LambdaQueryWrapper<PatrolReport>().eq(PatrolReport::getTaskId, taskId));
        return CollUtil.isEmpty(patrolReports) ? null : patrolReports.get(0);
    }

    @Override
    public PatrolReport createReport(Long taskId) {
        PatrolSubtaskCommonVo task = patrolSubtaskCommonService.queryById(taskId);
        if (ObjUtil.isNull(task)) {
            throw new ServiceException("任务不存在");
        }
        // 判断任务的状态是否为已完成，如果是则不能再从任务列表中开始巡店
        if ("FINISHED".equals(task.getStatus())) {
            throw new ServiceException("任务已完成");
        }
        // 查询模板
        if (task.getTemplateId() != null) {
            PatrolTemplate patrolTemplate = patrolTemplateMapper.selectById(task.getTemplateId());
            if (ObjUtil.isNull(patrolTemplate)) {
                throw new ServiceException("模板不存在");
            }
        }

        PatrolReport patrolReport = this.selectByTaskId(taskId);
        if (ObjUtil.isNotNull(patrolReport)) {
            return patrolReport;
        }
        // 修改任务状态
        patrolSubtaskCommonService.updateStatusAndTimeById(taskId, "PROCESSING", new Date().getTime(), null);

        patrolReport = new PatrolReport();
        patrolReport.setTaskId(taskId);
        patrolReport.setIsCheckDraft("1");
        patrolReport.setStatus("UNCOMMITTED");
        patrolReport.setTemplateId(patrolReport.getTemplateId());
        return patrolReport;
    }

    /**
     * 计算得分对象
     *
     * @param totalScoreTem 模板总分
     * @param hasProblemScore 有问题得分
     * @param notApplyScore 不适用得分
     * @return 计算得分对象
     */
    @NotNull
    private static CalculateScoreVo getCalculateScoreVo(BigDecimal totalScoreTem, BigDecimal hasProblemScore, BigDecimal notApplyScore) {
        BigDecimal totalGetScore = totalScoreTem.subtract(hasProblemScore).subtract(notApplyScore);
        CalculateScoreVo calculateScoreVo = new CalculateScoreVo();
        CalculatedItemScoreVo calculatedItemScoreVo = new CalculatedItemScoreVo();
        //模板总分
        calculatedItemScoreVo.setTotalScore(totalScoreTem);
        //评分项得分 = 总分-有问题和不适用的得分
        calculatedItemScoreVo.setTotalGetScore(totalGetScore);
        //不适用得分
        calculatedItemScoreVo.setInapplicableItemScore(notApplyScore);

        BigDecimal finalScore = BigDecimal.ZERO;
        BigDecimal subtract = totalScoreTem.subtract(notApplyScore);
        if (subtract.compareTo(BigDecimal.ZERO) != 0) {
             finalScore = totalGetScore.divide(totalScoreTem.subtract(notApplyScore), MathContext.DECIMAL32)
                    .multiply(totalScoreTem,MathContext.DECIMAL32);
        }
        calculateScoreVo.setTotalScore(finalScore.setScale(2,RoundingMode.HALF_UP));
        calculateScoreVo.setCalculatedItemScoreVo(calculatedItemScoreVo);
        return calculateScoreVo;
    }

    /**
     * 构建评分项集合;把所有的评分项，和子集合里面的评分项弄成一个新的集合
     *
     * @param nodes
     * @return
     */

    private List<PatrolTemplateNodeBo> buildNodes(List<PatrolTemplateNodeBo> nodes) {
        LinkedList<PatrolTemplateNodeBo> flattenedList = new LinkedList<>();
        for (PatrolTemplateNodeBo node : nodes) {
            flattenedList.add(node);
            if (node.getChildren() != null) {
                flattenedList.addAll(buildNodes(node.getChildren()));
            }
        }
        return flattenedList;

    }

    /**
     * 保存巡店报告动态详情
     * @param bo    巡店报告对象
     */
    private void saveReportDetail(PatrolReportBo bo) {
        Object detail = bo.getDetail();
        if (ObjUtil.isNotNull(detail)) {
            PatrolReportDetail patrolReportDetail = new PatrolReportDetail();
            patrolReportDetail.setDetails(detail);
            int insert = patrolReportDetailMapper.insert(patrolReportDetail);
            if (insert > 0) {
                bo.setDetailId(patrolReportDetail.getDetailId());
            }
        }
    }

    private void sendMsg(List<RemoteMessageBo> handlerMessageList) {
        if (CollUtil.isEmpty(handlerMessageList)) {
            return;
        }
        remoteMessageService.insertBatchByBo(handlerMessageList);
    }

    /**
     * 删除报告
     * @param storeId
     */

    @Override
    public void deletePatrolReport(Long storeId) {
        if(Objects.isNull(storeId)){
            throw new ServiceException("参数错误");
        }
        LambdaQueryWrapper<PatrolReport> wrapper  = new LambdaQueryWrapper<>();
        wrapper.eq(PatrolReport::getStoreId,storeId);
        List<PatrolReport> patrolReports = baseMapper.selectList(wrapper);
        if (CollUtil.isNotEmpty(patrolReports)){
            baseMapper.deleteBatchIds(patrolReports);
        }
    }
}
